﻿using FCSChart.Axis;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace FCSChart
{
    [TemplatePart(Name = "Part_XSlider", Type = typeof(Slider))]
    [TemplatePart(Name = "Part_YSlider", Type = typeof(Slider))]
    [TemplatePart(Name = "Part_XThreshold", Type = typeof(Path))]
    [TemplatePart(Name = "Part_YThreshold", Type = typeof(Path))]
    [TemplatePart(Name = "Part_XThresholdText", Type = typeof(TextBlock))]
    [TemplatePart(Name = "Part_YThresholdText", Type = typeof(TextBlock))]
    public class ChartInCollecting : ChartWithGraphicals
    {
        static ChartInCollecting()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ChartInCollecting), new FrameworkPropertyMetadata(typeof(ChartInCollecting)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            var tempXSlider = GetTemplateChild("Part_XSlider");
            if (tempXSlider != null && tempXSlider is Slider xSlider)
            {
                XSlider = xSlider;
                XSlider.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(XSlider_DragCompleted));
            }
            var tempYSlider = GetTemplateChild("Part_YSlider");
            if (tempYSlider != null && tempYSlider is Slider ySlider)
            {
                YSlider = ySlider;
                YSlider.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(YSlider_DragCompleted));
            }

            var tempXThreshold = GetTemplateChild("Part_XThreshold");
            if (tempXThreshold != null && tempXThreshold is Path xLine)
            {
                XLine = xLine;
                XLine.PreviewMouseLeftButtonDown += XLine_PreviewMouseLeftButtonDown;
                XLine.Loaded += (sender, e) =>
                {
                    DrawingXThreshold();
                };
            }
            var tempYThreshold = GetTemplateChild("Part_YThreshold");
            if (tempYThreshold != null && tempYThreshold is Path yLine)
            {
                YLine = yLine;
                YLine.PreviewMouseLeftButtonDown += YLine_PreviewMouseLeftButtonDown;
                YLine.Loaded += (sender, e) =>
                {
                    DrawingYThreshold();
                };
            }
            var tempXThreasholdText = GetTemplateChild("Part_XThresholdText");
            if (tempXThreasholdText != null && tempXThreasholdText is TextBlock xTbx) XText = xTbx;
            var tempYThreasholdText = GetTemplateChild("Part_YThresholdText");
            if (tempYThreasholdText != null && tempYThreasholdText is TextBlock yTbx) YText = yTbx;
        }


        #region 增益

        /// <summary>
        /// 是否可以编辑增益
        /// </summary>
        public bool CanChangeGain
        {
            get { return (bool)GetValue(CanChangeGainProperty); }
            set { SetValue(CanChangeGainProperty, value); }
        }
        public static readonly DependencyProperty CanChangeGainProperty = DependencyProperty.Register("CanChangeGain", typeof(bool), typeof(ChartInCollecting), new PropertyMetadata(true));

        /// <summary>
        /// 增益最小值
        /// </summary>
        public double MinGain
        {
            get { return (double)GetValue(MinGainProperty); }
            set { SetValue(MinGainProperty, value); }
        }
        public static readonly DependencyProperty MinGainProperty = DependencyProperty.Register("MinGain", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(0d));

        /// <summary>
        /// 增益最大值
        /// </summary>
        public double MaxGain
        {
            get { return (double)GetValue(MaxGainProperty); }
            set { SetValue(MaxGainProperty, value); }
        }
        public static readonly DependencyProperty MaxGainProperty = DependencyProperty.Register("MaxGain", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(4096d));

        /// <summary>
        /// 刻度间隔
        /// </summary>
        public double TickFrequency
        {
            get { return (double)GetValue(TickFrequencyProperty); }
            set { SetValue(TickFrequencyProperty, value); }
        }
        public static readonly DependencyProperty TickFrequencyProperty = DependencyProperty.Register("TickFrequency", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(1d));

        protected Slider XSlider { get; set; }
        protected Slider YSlider { get; set; }

        /// <summary>
        /// 显示x轴的增益
        /// </summary>
        public bool ShowXGain
        {
            get { return (bool)GetValue(ShowXGainProperty); }
            set { SetValue(ShowXGainProperty, value); }
        }
        public static readonly DependencyProperty ShowXGainProperty = DependencyProperty.Register("ShowXGain", typeof(bool), typeof(ChartInCollecting), new PropertyMetadata(false));
        /// <summary>
        /// 显示y轴的增益
        /// </summary>
        public bool ShowYGain
        {
            get { return (bool)GetValue(ShowYGainProperty); }
            set { SetValue(ShowYGainProperty, value); }
        }
        public static readonly DependencyProperty ShowYGainProperty = DependencyProperty.Register("ShowYGain", typeof(bool), typeof(ChartInCollecting), new PropertyMetadata(false));

        /// <summary>
        /// x轴增益值
        /// </summary>
        public double XGainValue
        {
            get { return (double)GetValue(XGainValueProperty); }
            set { SetValue(XGainValueProperty, value); }
        }
        public static readonly DependencyProperty XGainValueProperty = DependencyProperty.Register("XGainValue", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(1000d));
        /// <summary>
        /// y轴增益值
        /// </summary>
        public double YGainValue
        {
            get { return (double)GetValue(YGainValueProperty); }
            set { SetValue(YGainValueProperty, value); }
        }
        public static readonly DependencyProperty YGainValueProperty = DependencyProperty.Register("YGainValue", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(1000d));

        /// <summary>
        /// x轴增益发生变化
        /// </summary>
        public ICommand XGainChangedCommand
        {
            get { return (ICommand)GetValue(XGainChangedCommandProperty); }
            set { SetValue(XGainChangedCommandProperty, value); }
        }
        public static readonly DependencyProperty XGainChangedCommandProperty = DependencyProperty.Register("XGainChangedCommand", typeof(ICommand), typeof(ChartInCollecting), new PropertyMetadata(null));

        /// <summary>
        /// y轴增益发生变化
        /// </summary>
        public ICommand YGainChangedCommand
        {
            get { return (ICommand)GetValue(YGainChangedCommandProperty); }
            set { SetValue(YGainChangedCommandProperty, value); }
        }
        public static readonly DependencyProperty YGainChangedCommandProperty = DependencyProperty.Register("YGainChangedCommand", typeof(ICommand), typeof(ChartInCollecting), new PropertyMetadata(null));

        private void XSlider_DragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (XSlider != null) XGainChangedCommand?.Execute(XSlider.Value);
        }
        private void YSlider_DragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (YSlider != null) YGainChangedCommand?.Execute(YSlider.Value);
        }
        #endregion

        #region 阈值
        /// <summary>
        /// 阈值最小值,可等于
        /// </summary>
        public double MinThreshold
        {
            get { return (double)GetValue(MinThresholdProperty); }
            set { SetValue(MinThresholdProperty, value); }
        }
        public static readonly DependencyProperty MinThresholdProperty = DependencyProperty.Register("MinThreshold", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(0d));
        /// <summary>
        /// 阈值最大值，可等于
        /// </summary>
        public double MaxThreshold
        {
            get { return (double)GetValue(MaxThresholdProperty); }
            set { SetValue(MaxThresholdProperty, value); }
        }
        public static readonly DependencyProperty MaxThresholdProperty = DependencyProperty.Register("MaxThreshold", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(65535d));

        /// <summary>
        /// 显示x轴阈值
        /// </summary>
        public bool ShowXThreshold
        {
            get { return (bool)GetValue(ShowXThresholdProperty); }
            set { SetValue(ShowXThresholdProperty, value); }
        }
        public static readonly DependencyProperty ShowXThresholdProperty = DependencyProperty.Register("ShowXThreshold", typeof(bool), typeof(ChartInCollecting), new PropertyMetadata(false));

        /// <summary>
        /// 显示y轴阈值
        /// </summary>
        public bool ShowYThreshold
        {
            get { return (bool)GetValue(ShowYThresholdProperty); }
            set { SetValue(ShowYThresholdProperty, value); }
        }
        public static readonly DependencyProperty ShowYThresholdProperty = DependencyProperty.Register("ShowYThreshold", typeof(bool), typeof(ChartInCollecting), new PropertyMetadata(false));

        /// <summary>
        /// x轴阈值
        /// </summary>
        public double XThresholdValue
        {
            get { return (double)GetValue(XThresholdValueProperty); }
            set { SetValue(XThresholdValueProperty, value); }
        }
        public static readonly DependencyProperty XThresholdValueProperty = DependencyProperty.Register("XThresholdValue", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(5000d, (sender, e) =>
        {
            if (sender is ChartInCollecting chart) chart.DrawingXThreshold();
        }));

        /// <summary>
        /// y轴阈值
        /// </summary>
        public double YThresholdValue
        {
            get { return (double)GetValue(YThresholdValueProperty); }
            set { SetValue(YThresholdValueProperty, value); }
        }
        public static readonly DependencyProperty YThresholdValueProperty = DependencyProperty.Register("YThresholdValue", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(5000d, (sender, e) =>
        {
            if (sender is ChartInCollecting chart) chart.DrawingYThreshold();
        }));

        /// <summary>
        /// x轴上的阈值发生变化命令
        /// </summary>
        public ICommand XThresholdChangedCommand
        {
            get { return (ICommand)GetValue(XThresholdChangedCommandProperty); }
            set { SetValue(XThresholdChangedCommandProperty, value); }
        }
        public static readonly DependencyProperty XThresholdChangedCommandProperty = DependencyProperty.Register("XThresholdChangedCommand", typeof(ICommand), typeof(ChartInCollecting), new PropertyMetadata(null));

        /// <summary>
        /// y轴上的阈值发生变化命令
        /// </summary>
        public ICommand YThresholdChangedCommand
        {
            get { return (ICommand)GetValue(YThresholdChangedCommandProperty); }
            set { SetValue(YThresholdChangedCommandProperty, value); }
        }
        public static readonly DependencyProperty YThresholdChangedCommandProperty = DependencyProperty.Register("YThresholdChangedCommand", typeof(ICommand), typeof(ChartInCollecting), new PropertyMetadata(null));

        /// <summary>
        /// 是否可以编辑阈值
        /// </summary>
        public bool CanChangeThreshold
        {
            get { return (bool)GetValue(CanChangeThresholdProperty); }
            set { SetValue(CanChangeThresholdProperty, value); }
        }
        public static readonly DependencyProperty CanChangeThresholdProperty = DependencyProperty.Register("CanChangeThreshold", typeof(bool), typeof(ChartInCollecting), new PropertyMetadata(true));

        /// <summary>
        /// 阈值调节控制点的宽度的一半值
        /// </summary>
        public double ThresholdPointLength
        {
            get { return (double)GetValue(ThresholdPointLengthProperty); }
            set { SetValue(ThresholdPointLengthProperty, value); }
        }
        public static readonly DependencyProperty ThresholdPointLengthProperty = DependencyProperty.Register("ThresholdPointLength", typeof(double), typeof(ChartInCollecting), new PropertyMetadata(6d, (sender, e) =>
        {
            if (sender is ChartInCollecting chart)
            {
                chart.DrawingXThreshold();
                chart.DrawingYThreshold();
            }
        }));

        public TextBlock XText { get; set; }
        public TextBlock YText { get; set; }
        protected Path XLine { get; set; }
        protected Path YLine { get; set; }
        bool isMoveXLine = false;
        bool isMoveYLine = false;
        private void XLine_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (CanChangeThreshold) isMoveXLine = true;
        }

        private void YLine_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (CanChangeThreshold) isMoveYLine = true;
        }

        protected override void Panel_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMoveXLine)
            {
                var point = e.GetPosition(ViewPanel);
                var value = XAxis.GetLocationValue(point.X);
                if (value >= MinThreshold && value <= MaxThreshold) XThresholdValue = value;
                e.Handled = true;
            }
            else if (isMoveYLine)
            {
                var point = e.GetPosition(ViewPanel);
                var value = YAxis.GetLocationValue(point.Y);
                if (value >= MinThreshold && value <= MaxThreshold) YThresholdValue = value;
                e.Handled = true;
            }
            else base.Panel_MouseMove(sender, e);
        }

        protected override void Panel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isMoveXLine)
            {
                isMoveXLine = false;
                XThresholdChangedCommand?.Execute(XThresholdValue);
            }
            else if (isMoveYLine)
            {
                isMoveYLine = false;
                YThresholdChangedCommand?.Execute(YThresholdValue);
            }
            else base.Panel_MouseLeftButtonUp(sender, e);
        }

        protected void DrawingXThreshold()
        {
            if (ShowXThreshold && XAxis != null && XLine != null && !double.IsNaN(XThresholdValue) && !double.IsInfinity(XThresholdValue) && ViewPanel != null && ViewPanel.IsLoaded)
            {
                var temp = XAxis.GetValueLocation(XThresholdValue);
                var length = ViewPanel.ActualHeight;
                var halflength = length / 2;
                if (!double.IsNaN(temp) && !double.IsInfinity(temp))
                {
                    //XLine.X1 = temp;
                    StreamGeometry geometry = new StreamGeometry();
                    using (StreamGeometryContext sgc = geometry.Open())
                    {
                        sgc.BeginFigure(new Point(temp, 0), false, false);
                        sgc.LineTo(new Point(temp, ViewPanel.ActualHeight), true, false);
                        sgc.BeginFigure(new Point(temp, halflength + ThresholdPointLength * 2), true, true);
                        sgc.PolyLineTo(new Point[] { new Point(temp + ThresholdPointLength, halflength), new Point(temp, halflength - ThresholdPointLength * 2), new Point(temp - ThresholdPointLength, halflength) }, false, false);
                        sgc.Close();
                    }
                    geometry.Freeze();
                    XLine.Data = geometry;
                    if (XText != null) XText.Margin = new Thickness(temp + ThresholdPointLength, halflength + ThresholdPointLength, 0, 0);
                }
            }
        }

        protected void DrawingYThreshold()
        {
            if (ShowYThreshold && YAxis != null && YLine != null && !double.IsNaN(YThresholdValue) && !double.IsInfinity(YThresholdValue) && ViewPanel != null && ViewPanel.IsLoaded)
            {
                var temp = YAxis.GetValueLocation(YThresholdValue);
                var length = ViewPanel.ActualWidth;
                var halflength = length / 2;
                if (!double.IsNaN(temp) && !double.IsInfinity(temp))
                {
                    //YLine.Y1 = temp;
                    StreamGeometry geometry = new StreamGeometry();
                    using (StreamGeometryContext sgc = geometry.Open())
                    {
                        sgc.BeginFigure(new Point(0, temp), false, false);
                        sgc.LineTo(new Point(length, temp), true, false);
                        sgc.BeginFigure(new Point(halflength + ThresholdPointLength * 2, temp), true, true);
                        sgc.PolyLineTo(new Point[] { new Point(halflength, temp + ThresholdPointLength), new Point(halflength - ThresholdPointLength * 2, temp), new Point(halflength, temp - ThresholdPointLength) }, false, false);
                        sgc.Close();
                    }
                    geometry.Freeze();
                    YLine.Data = geometry;
                    if (YText != null) YText.Margin = new Thickness(halflength + ThresholdPointLength, temp + ThresholdPointLength, 0, 0);
                }
            }
        }
        #endregion
        protected override void DrawingGraphicals()
        {
            base.DrawingGraphicals();
            DrawingXThreshold();
            DrawingYThreshold();
        }
    }
}
